package com.xiaojie.aspect;

import com.xiaojie.annotation.DataCode;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author xiaojie
 * @version 1.0
 * @description: 切面类
 * @date 2022/6/11 20:37
 */
@Aspect
@Component
public class DataAspect {
    @Autowired
    private DataAspectService dataAspectService;

    private static final LocalVariableTableParameterNameDiscoverer parameterNameDiscovere = new LocalVariableTableParameterNameDiscoverer();

    @Around(value = "@annotation(com.xiaojie.annotation.DataCode)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取注解上的方法
        Method method = getMethod(joinPoint);
        //获取方法上的注解
        DataCode annotation = method.getDeclaredAnnotation(DataCode.class);
        DataCode.Type type = annotation.type();
        //获取注解上的参数
        String name = getAnnotationValue(annotation.name(), joinPoint);
        String scope = getAnnotationValue(annotation.scope(), joinPoint);
        String shopCode = getAnnotationValue(annotation.shopCode(), joinPoint);
        String shopName = getAnnotationValue(annotation.shopName(), joinPoint);
        String value = getAnnotationValue(annotation.value(), joinPoint);
        //获取目标对象方法参数
        Object[] args = joinPoint.getArgs();
        if (type.equals(DataCode.Type.USER)) {
            //类型是用户
            dataAspectService.userAspect(args[0], value, name, scope, shopName, shopCode);
        } else if (type.equals(DataCode.Type.SHOP)) {
            //类型是店铺
        }
        Object result = joinPoint.proceed(args);
        return result;
    }

    /**
     * @description:
     * @param: 获取切面上的方法
     * @param: joinPoint
     * @return: java.lang.reflect.Method
     * @author xiaojie
     * @date: 2022/6/11 20:42
     */
    private Method getMethod(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
        //获取方法签名
        String methodName = joinPoint.getSignature().getName();
        // 获取目标对象
        Class<? extends Object> targetClass = joinPoint.getTarget().getClass();
        // 获取目标对象类型
        Class[] par = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
        // 获取目标对象方法
        Method objMethod = targetClass.getDeclaredMethod(methodName, par);
        return objMethod;
    }

    private String getAnnotationValue(String annotationName, ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
        //获取被调用的方法
        Method method = getMethod(joinPoint);
        Object[] args = joinPoint.getArgs();
        //获取方法中定义的参数名称
        LocalVariableTableParameterNameDiscoverer localVariableTable = new LocalVariableTableParameterNameDiscoverer();
        String[] paraNameArr = localVariableTable.getParameterNames(method);
        //使用SPEL进行key的解析
        ExpressionParser parser = new SpelExpressionParser();
        //SPEL上下文
        StandardEvaluationContext context = new StandardEvaluationContext();
        //把方法参数放入SPEL上下文中
        for(int i=0;i<paraNameArr.length;i++) {
            context.setVariable(paraNameArr[i], args[i]);
        }
        String resultName = null;
        // 使用变量方式传入业务动态数据
        if(annotationName.matches("^#.*.$")) {
            resultName = parser.parseExpression(annotationName).getValue(context, String.class);
        }
        System.out.println("获取到的参数是》》》》》》》》"+resultName);

        return resultName;
    }

}
